package com.ecspace.knowledgegraphapi.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ecspace.knowledgegraphapi.domain.dto.DrawParams;
import com.ecspace.knowledgegraphapi.domain.dto.NodeDTO;
import com.ecspace.knowledgegraphapi.domain.entity.Node;
import com.ecspace.knowledgegraphapi.domain.entity.Relation;
import com.ecspace.knowledgegraphapi.service.IDrawGraphService;
import com.ecspace.knowledgegraphapi.service.INodeService;
import com.ecspace.knowledgegraphapi.service.IRelationService;
import com.ecspace.knowledgegraphapi.util.RandomUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: cs
 * @date: 2024-07-01 14:35:17
 * @since: 1.0
 */
@Service
public class DrawGraphServiceImpl implements IDrawGraphService {


    @Autowired
    private INodeService nodeService;

    @Autowired
    private IRelationService relationService;





    @Override
    public JSONObject getLabel() {
        JSONObject label = new JSONObject();
        label.put("show", true);
        return label;
    }

    @Override
    public JSONObject draw(DrawParams params) {
        JSONObject result = new JSONObject();
        String baseNodeId = params.getBaseNodeId();
        JSONObject series = new JSONObject();

        series.put("type", "graph");
        series.put("draggable", true);
        series.put("layout", "none");
        series.put("symbolSize", 50);
        series.put("roam", true);
        series.put("label", getLabel());
        series.put("edgeSymbol", getEdgeSymbol("circle", "arrow"));
        series.put("edgeSymbolSize", getEdgeSymbol(4, 10));
        series.put("edgeLabel", getEdgeLabel());
        JSONArray data = getData(baseNodeId);
        series.put("data", data);
        JSONArray links = getLinks(baseNodeId);
        series.put("links", links);
        series.put("lineStyle", getLineStyle());
        series.put("expandAndCollapse", true);
        JSONArray seriesArray = new JSONArray();
        seriesArray.add(series);

        result.put("tooltip", new JSONObject());
        result.put("animationDurationUpdate", 1500);

        result.put("animationEasingUpdate", "quinticInOut");
        result.put("series", seriesArray);

        System.out.println("============================================");
        System.out.println(JSON.toJSONString(result));
        System.out.println("============================================");
        return result;
    }

    @Override
    public JSONArray getEdgeSymbol(Object o1, Object o2) {
        JSONArray array = new JSONArray();
        array.add(o1);
        array.add(o2);
        return array;
    }

    @Override
    public JSONObject getEdgeLabel() {
        JSONObject label = new JSONObject();
        label.put("fontSize", 20);
        return label;
    }


    @Override
    public JSONArray getData(String baseNodeId) {
        List<Relation> list = relationService.list();
        List<String> fromIds = list.stream().map(Relation::getFromId)
                .distinct()
                .collect(Collectors.toList());

        List<String> toIds = list.stream().map(Relation::getToId)
                .distinct()
                .collect(Collectors.toList());

        List<String> ids = new ArrayList<>();
        ids.addAll(fromIds);
        ids.addAll(toIds);
        if (ids.isEmpty()) {
            return new JSONArray();
        }
        List<Node> nodes = nodeService.listByIds(ids);
        JSONArray data = new JSONArray();
        int size = nodes.size();
        double radius = 10;
        double angleStep = Math.PI * 2 / (size - 1);
        Node centerNode = null;
        for (Node node : nodes) {
            if (baseNodeId.equals(node.getId())) {
                JSONObject item = new JSONObject();
                item.put("name", node.getLabel());
                item.put("category", 1);
                item.put("x", 100);
                item.put("y", 100);
                data.add(item);
                centerNode = node;
                break;
            }
        }
        if (centerNode != null) {
            nodes.remove(centerNode);
        }

        for (int i = 0; i < size - 1; i++) {
            Node node = nodes.get(i);
            JSONObject item = new JSONObject();
            item.put("name", node.getLabel());
            double angle = i * angleStep;
            double x = 100 + radius * Math.cos(angle);
            double y = 100 + radius * Math.sin(angle);
            item.put("x", x);
            item.put("y", y);
            data.add(item);
        }
        return data;
    }

    @Override
    public JSONArray getLinks(String baseNodeId) {

        List<Relation> list = relationService.list();
        List<Node> nodeList = nodeService.list();
        Map<String, String> nodeLabelMap = nodeList.stream().collect(Collectors.toMap(Node::getId, Node::getLabel));
        JSONArray links = new JSONArray();
        for (Relation relation : list) {
            String fromId = relation.getFromId();
            String toId = relation.getToId();
            String name = relation.getName();

            if (nodeLabelMap.containsKey(fromId) && nodeLabelMap.containsKey(toId)) {
                String sourceLabel = nodeLabelMap.get(fromId);
                String targetLabel = nodeLabelMap.get(toId);
                JSONObject item = new JSONObject();
                item.put("source", sourceLabel);
                item.put("target", targetLabel);
                JSONObject label = new JSONObject();
                label.put("show", true);
                label.put("formatter", name);
                label.put("fontSize", 10);
                item.put("label", label);
                links.add(item);
            }
        }
        return links;
    }


    @Override
    public JSONObject getLineStyle() {
        JSONObject obj = new JSONObject();
        obj.put("opacity", 0.9);
        obj.put("width", 2);
        obj.put("curveness", 0);
        return obj;
    }






}
